/*
* ============================================================================
*  Name        : platform_less.h
*  Part of     : Finite state machine utilities
*  Description : Platform abstruction layer
*  Version     : %version: %
*  
*
* ============================================================================
*/
/**
 * @file sea_platform_less.h
 *
 * @ingroup Platforms
 */

#if !defined( __sea_platform_less_h__ )
#define __sea_platform_less_h__

#include <string>
#include <vector>
#include <map>
#include <typeinfo>
#include <stdlib.h>
#include <assert.h>
#include <time.h>

#include "sea_assert.h"

using namespace std;

#pragma warning( disable : 4355 )
#pragma warning( disable : 4189 )

namespace sea
{
    #define SEA_PRETTY_FUNCTION __FUNCTION__

    typedef std::string String;
    typedef int OsThreadHandle;

    /**
     * @class OsThread
     * @brief Dummy thread for os-less environment
     *
     * @ingroup Platforms
     */
    class OsThread : public Object
    {
    public:
        static OsThreadHandle currentThreadId( ){ return 0; }
        virtual void exec( ) { }
        void start( ) { thread->exec( ); }
        void wait( i::uint32 time = -1 ){ SEA_UNUSED( time ); }
        OsThreadHandle id( ){ return 0; }
        void setPriority( OsThreadPriority value ){ SEA_UNUSED( value ); }
        bool isRunning( ){ return true; }
    };

    /**
     * @class OsSemaphore
     * @brief Dummy semaphore for os-less environment
     *
     * @ingroup Platforms
     */
    class OsSemaphore : public Object
    {
    public:
        OsSemaphore( int counter = 0 ) : m_counter( counter ) { }
        ~OsSemaphore( ) { }

        virtual void signal( int increment = 1 ) 
        { 
            // In OS less environment we have to be able to
            // wake the system up. See wait( )
            m_counter += increment; 
        }

        virtual bool wait( int decrement = 1 )
        {
            int counter = decrement;
            while ( decrement-- )
            {
                while ( m_counter == 0 )
                { 
                    // Here in os less environemt we should go
                    // Idle instruction to save power
                }

                m_counter--;
                counter--;
            }
            return counter == 0;
        }
    protected:
        int m_counter;
    };

    /**
     * @class OsMutex
     * @brief Dummy mutex for os-less environment
     *
     * @ingroup Platforms
     */
    class OsMutex : public Object
    {
    public:
        OsMutex( int aInterrupt = 0 ) : m_interrupt( aInterrupt ) { }
        bool try_enter( ) 
        {
            // If interrupt is disabled return false
            enter( );
            return true;
        }
        void enter( ){ /* Disable m_interrupt */ }
        void leave( ){ /* Enable m_interrupt */ }

        /**
         * @class Scoped
         * @brief Mutex scoped lock/unlock
         *
         * @ingroup Platforms
         */
        class Scoped
        {
        public:
            Scoped( OsMutex* critical_section, bool do_try = false );
            ~Scoped( );
        private:
            OsMutex* m_mutex;
        };
    private:
        int m_interrupt;
    };

    /**
     * @class OsSpinlock
     * @brief Dummy spinlock
     *
     * @ingroup Platforms
     */
    class OsSpinlock
    {
    public:
        OsSpinlock( ){ }
        ~OsSpinlock( ) { }

        void enter( ) { }
        void leave( ) { }

        /**
         * @class Scoped
         * @brief Spinlock scoped lock/unlock
         *
         * @ingroup Platforms
         */
        class Scoped
        {
        public:
            Scoped( OsSpinlock* critical_section ): m_lock( critical_section ) { if ( m_lock ) m_lock->enter( ); }
            ~Scoped( ){ if ( m_lock ) m_lock->leave( ); }
        private:
            OsSpinlock* m_lock;
        };
    };

    /**
     * @class OsSignal
     * @brief Dummy signal for os-less environment
     *
     * @ingroup Platforms
     */
    class OsSignal : public OsSemaphore
    {
    public:
        OsSignal( ) : OsSemaphore( 0 ) { }
        bool wait( int timeout )
        {
            OsMutex::Scoped protect( &m_mutex );

            // True - wait period is finished, False - otherwise
            return !OsSemaphore::wait( 1, timeout ); 
        }
        void wakeup( ){ OsSemaphore::signal( ); }
    private:
        OsMutex m_mutex;
    };

    /**
     * @class OsTime
     * @brief Basic millisecond timer
     *
     * @ingroup Platforms
     */
    class OsTime
    {
    public:
        OsTime( ) : m_current( get_time_in_ms( ) { }

        /**
         * Start counting time
         */
        void start( ){ m_current = get_time_in_ms( ); }

        /**
         * Get elapsed time
         *
         * @return Time in milliseconds
         */
        int elapsed( ){ return get_time_in_ms( ) - m_current; }
    
        /**
         * Get time in milliseconds. Replace with target specific implementation
         */
        static int get_time_in_ms( )
        {
            static int seed = 0;
            // Precision is 1 / CLOCKS_PER_SEC ms
            int tmp = ( int )( ( 1000. * clock( ) ) / CLOCKS_PER_SEC  );
            if( seed == 0 )
            {
                seed = tmp;
                return 0;
            }
            return tmp - seed;
        }
    private:
        int m_current;
    };

}
#endif
